local args = ngx.req.get_uri_args()

local uid = args.uid

if nil == uid then
    ngx.say([[{"code":10000,"message":"请登录后参与","data":{"is_winning":false,"surplus_times":0}}]])
    return
end

local type = args.type

if nil == type then
    ngx.say([[{"code":10000,"message":"抽奖类型为空","data":{"is_winning":false,"surplus_times":0}}]])
    return
end

local act_id = args.act_id
if nil == act_id then
    ngx.say([[{"code":10000,"message":"活动id不能为空","data":{"is_winning":false,"surplus_times":0}}]])
    return
end

local redis_client = require "lib.redis"
local redis = redis_client:new()
local rules = redis:hmget('rules:'..act_id, 'limit_type', 'limit_times', 'start_at', 'end_at', 'is_paused')

if nil == rules then
    ngx.say('{"code":10000,"message":"活动不存在","data":{"allowed":false,"type":"not-found","surplus_times":0}}')
    return
end

local time = ngx.time()
local is_paused = tonumber(rules[5])
local start_at = rules[3] or 0
local end_at = rules[4] or (time + 1)

--验证活动是否暂停
if is_paused == 1 then
    ngx.say('{"code":10000,"message":"活动已暂停","data":{"allowed": false,"type":"paused","surplus_times":0}}')
    return
end

--验证活动时间
if time > tonumber(end_at) then
    ngx.say('{"code":10000, "message":"活动已经结束"}')
    return
end

if time < tonumber(start_at) then
    ngx.say('{"code":10000, "message":"活动还未开始"}')
    return
end

local checked = ngx.location.capture("/draw/times", {
    args={
        uid=uid,
        act_id=act_id
    }
})

local surplus_times = tonumber(checked.body) or 0

if  surplus_times <= 0 then
    ngx.say([[{"code":10000,"message":"您的抽奖次数已用完","data":{"is_winning":false,"surplus_times":0}}]])
    return
end

-- 所有验证通过，算一次操作，故减少一次库存
surplus_times = surplus_times - 1

ngx.record_user()
local prizes_json, err = redis:get("activity:"..act_id..":prizes")

if err ~= nil then
    ngx.say('{"code":10000,"message":"redis error:', err,'"}')
    return
end

local times_key = "times:"..act_id..":"..uid
-- 记录次数
redis:hincrby(times_key, 'total', 1)
redis:hincrby(times_key, ngx.today(), 1)
redis:incr("participants:"..act_id)

if nil == prizes_json then
    ngx.say('{"code":200,"message":"很遗憾，您没能中奖","data":{"is_winning":false,"surplus_times":', surplus_times, '}}')
    return
end

local json = require "cjson"
local prizes = json.decode(prizes_json)

-- 获取到活动的奖品个数
local prizes_number = #prizes

if 0 == prizes_number then
    ngx.say('{"code":200,"message":"抠门儿的主办方好像没设置奖品","data":{"is_winning":false,"surplus_times":', surplus_times, '}}')
    return
end

-- 随机因子
math.randomseed(tonumber(tostring(os.time()):reverse():sub(1,6)))
-- 随机到奖品
local hit = math.random(1, prizes_number)

if not prizes[hit] then
    ngx.say('{"code":200,"message":"抠门儿的主办方好像没设置奖品","data":{"is_winning":false,"surplus_times":', surplus_times, '}}')
    return
end

local prize = prizes[hit]
local prize_win_limit_key = "winning:limit:"..act_id..":"..prize.id
local user_win = redis:hget(prize_win_limit_key, uid);
local user_win_limit = tonumber(user_win) or 0
local rule_win_limit = tonumber(prize.winning_limit) or 0

if rule_win_limit ~= 0 and user_win_limit >= rule_win_limit then
    ngx.say('{"code":200,"message":"很遗憾，您没能中奖","data":{"is_winning":false,"surplus_times":', surplus_times, '}}')
    return
end

local now = ngx.now()

local is_expired = false

if prize.expired_start and prize.expired_end then
    if now >= prize.expired_start and now <= prize.expired_end then
        is_expired = true
    end
else
    is_expired = true
end

local prize_stock_key = "stock:"..act_id..":"..prize.id
local stock, err = redis:get(prize_stock_key)
local surplus = tonumber(stock)

if err ~= nil then
    ngx.say('{"code":10000,"message":"redis error:', err,'"}')
    return
end

local need_set_stock = false

if surplus == nil then
    -- 注意这里，使用的是可用库存
    surplus = prize.surplus
    need_set_stock = true
end

local is_winner = false

if surplus >= 1 then
    local factor = math.random()
    -- local factor = 0.1

    if factor <= prize.winning_probability and is_expired then
        -- 生成兑奖id
        local uuid = require "lib.uuid"
        uuid.seed()
        local draw_id = uuid.generate_v4()
        prize.draw_id = draw_id
        -- and 2 == prize.voucher_type
        if "coupon" == prize.type_code or "entity" == prize.type_code then
            local voucher_code, err = redis:spop("voucher:codes:"..prize.id)
            prize.voucher_code = voucher_code or ""
        end

        -- 拼装日志
        local tenant_id = args.TenantID or ""
        local openid = args.open_id or uid
        local uniqueid = string.lower(tenant_id..openid)
        local template = [[{"id":"%s","activity_id":"%s","prize_id":"%s","open_id":"%s","coupon":"%s","created_at":%d}]]
        local log = string.format(template, draw_id, act_id, prize.id, uniqueid, prize.voucher_code, now)
        -- 减库存， 写日志
        -- 事务开始
        redis:multi()
        -- 如果没有库存，则写入库存
        if need_set_stock then
            redis:set(prize_stock_key, surplus)
        end
        -- 减少库存
        redis:decr(prize_stock_key)
        -- 写日志
        redis:lpush("draw:records", log)
        redis:hincrby(prize_win_limit_key, uid, 1)
        -- 执行事务
        local ok, err = redis:exec()

        if ok then
            is_winner = true
        else
            redis:discard()
            ngx.say('{"code":10000,"message":"', err,'"}')
            return
        end
    end
end

if is_winner then
    ngx.say('{"code":200,"message":"恭喜您中奖了","data":{"is_winning":true,"prize":', json.encode(prize), ',"surplus_times":', surplus_times, '}}')
else
    ngx.say('{"code":200,"message":"很遗憾，您没能中奖","data":{"is_winning":false,"surplus_times":', surplus_times, '}}')
end
